#import "XsdkFlutterPlugin.h"
#import <Flutter/FlutterCodecs.h>

#import "XSDK.h"
#import "XSDKModuleManager.h"

//========================================================================================================
@interface XSDKCallBack
: NSObject<IXSDKCallback>{
    FlutterResult result;
}

@end

@implementation XSDKCallBack


-(void)setResult: (FlutterResult )result{
    self->result = result;
}

-(void)onSuccess: (NSString*)ret;
{
    result(ret);
}
-(void)onFaild: (NSString*) ret
{
    result([FlutterError errorWithCode:@"onFaild" message:ret details:nil]);
}
@end
//====================================================================================================
@interface XSDKIAPCallback : NSObject<IIAPCallback>
    @property (nonatomic, strong) FlutterEventSink eventSink;
@end

@implementation XSDKIAPCallback
-(void)setChannel: (FlutterEventSink)eventSink {
    self.eventSink = eventSink;
}
    
-(void)onPayResult:(NSString*) ret{
    NSDictionary *dict = @{
        @"data": ret,
        @"event":@"onIAPEvent"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}
    
@end

//========================================================================================================
@interface XBannerCallBack
: NSObject<IBannerAdEventCallBack>{
    int objectId;
}
@property (nonatomic, strong) FlutterEventSink eventSink;
@end

@implementation XBannerCallBack
-(void)setChannel: (FlutterEventSink)eventSink :(int) objectId {
    self.eventSink = eventSink;
    self->objectId = objectId;
}

-(void)onLoad:(NSString*) ret;
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onLoad",
        @"objectId": @(self->objectId),
        @"event":@"createBannerAd"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
    
}

-(void)onHide
{
    NSDictionary *dict = @{
        @"method": @"onHide",
        @"objectId": @(self->objectId),
        @"event":@"createBannerAd"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}

-(void)onError:(NSString*) ret
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onError",
        @"event":@"createBannerAd",
        @"objectId": @(self->objectId)
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}

@end
//========================================================================================================
@interface XRewardedVideoAdCallBack
: NSObject<IRewardedVideoAdEventCallBack>{
    int objectId;
}
@property (nonatomic, strong) FlutterEventSink eventSink;
@end

@implementation XRewardedVideoAdCallBack
-(void)setChannel: (FlutterEventSink)eventSink :(int) objectId {
    self.eventSink = eventSink;
    self->objectId = objectId;
}


-(void)onLoad:(NSString*) ret;
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onLoad",
        @"objectId": @(self->objectId),
        @"event":@"createRewardedVideoAd"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
    
}

-(void)onClose
{
    NSDictionary *dict = @{
        @"method": @"onClose",
        @"objectId": @(self->objectId),
        @"event":@"createRewardedVideoAd"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}


-(void)onReward
{
    NSDictionary *dict = @{
        @"method": @"onReward",
        @"objectId": @(self->objectId),
        @"event":@"createRewardedVideoAd"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}

-(void)onError:(NSString*) ret
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onError",
        @"event":@"createRewardedVideoAd",
        @"objectId": @(self->objectId)
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}

@end
//========================================================================================================
@interface XSplashAdCallBack
: NSObject<ISplashAdCallBack>{
    int objectId;
}
@property (nonatomic, strong) FlutterEventSink eventSink;
@end

@implementation XSplashAdCallBack
-(void)setChannel: (FlutterEventSink)eventSink :(int) objectId {
    self.eventSink = eventSink;
    self->objectId = objectId;
}


-(void)onLoad:(NSString*) ret;
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onLoad",
        @"objectId": @(self->objectId),
        @"event":@"createSplashAD"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
    
}

-(void)onDismissed
{
    NSDictionary *dict = @{
        @"method": @"onDismissed",
        @"objectId": @(self->objectId),
        @"event":@"createSplashAD"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}


-(void)onClicked
{
    NSDictionary *dict = @{
        @"method": @"onClicked",
        @"objectId": @(self->objectId),
        @"event":@"createSplashAD"
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}

-(void)onError:(NSString*) ret
{
    NSDictionary *dict = @{
        @"ret": ret,
        @"method": @"onError",
        @"event":@"createSplashAD",
        @"objectId": @(self->objectId)
    };
    
    NSError *error = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    self.eventSink(jsonString);
}
@end
//========================================================================================================


@implementation XsdkFlutterPlugin
{
    NSMutableDictionary* mAdObjMap;
    
    int numId;
    FlutterMethodChannel* channel;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                     methodChannelWithName:@"xsdk_flutter"
                                     binaryMessenger:[registrar messenger]];
    XsdkFlutterPlugin* instance = [[XsdkFlutterPlugin alloc] init];
    [registrar addMethodCallDelegate:instance channel:channel];
    instance->channel =channel;
    
    
    FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:@"xsdk_flutter_event" binaryMessenger:[registrar messenger]];
    [eventChannel setStreamHandler:instance];
}


-(id)init
{
    if(self=[super init])
    {
        self->mAdObjMap = [NSMutableDictionary  dictionaryWithCapacity:0];
        self->numId = 0;
    }
    return self;
}

-(int)genNumber{
    return ++(self->numId);
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    if ([@"getPlatformVersion" isEqualToString:call.method]) {
        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
    }else if([@"hasSDK" isEqualToString:call.method]) {
        NSString * jsonData = call.arguments;
        bool ret = [XSDK  hasSDK:jsonData];
        result(@(ret));
    }else if([@"initSDK" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  initSDK:jsonData :callBack];
    }else if([@"isInitSDK" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        bool ret = [XSDK  isInitSDK:jsonData];
        result(@(ret));
    }else if([@"login" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  login:jsonData :callBack];
    }else if([@"logout" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  logout:jsonData :callBack];
    }else if([@"pay" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  pay:jsonData :callBack];
    }else if([@"finishPay" isEqualToString:call.method]) {
        NSString * jsonData = call.arguments;
        [ XSDK finishPay:jsonData ];
        result(nil);
    }else if ([@"requestProduct" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  requestProduct:jsonData :callBack];
    }else if ([@"queryProduct" isEqualToString:call.method]) {
        XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
        [callBack setResult:result];
        NSString * jsonData = call.arguments;
        [ XSDK  queryProduct:jsonData :callBack];
    }else if ([@"onIPAEvent" isEqualToString:call.method]) {
        XSDKIAPCallback * callBack =  [[XSDKIAPCallback alloc] init];
        [ callBack setChannel:self.eventSink];
        [ XSDK  onIPAEvent :callBack];
    }
    
    
    
    
    else if([@"postEvent" isEqualToString:call.method]) {
        [XSDK postEvent:call.arguments];
        result(nil);
    }else if([@"share" isEqualToString:call.method]) {
         XSDKCallBack * callBack =  [[XSDKCallBack alloc] init];
            [callBack setResult:result];
            NSString * jsonData = call.arguments;
            [ XSDK  share:jsonData :callBack];
       
    }else if([@"createBannerAd"isEqualToString:call.method]) {
        int objectId = [self genNumber];
        XBannerCallBack* callcallBack =  [[XBannerCallBack alloc] init];
        
        [callcallBack setChannel:self.eventSink :objectId];
        id<IBannerAd> bannerAd = [XSDK createBannerAd:call.arguments :callcallBack];
        [self->mAdObjMap setObject:bannerAd forKey:@(objectId)];
        result(@(objectId));
    }else if([@"showBannerAd" isEqualToString:call.method]) {
        @try {   NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<IBannerAd> bannerAd = self->mAdObjMap[@(objectId)];
            [bannerAd show:[data[@"params"] stringValue]];
        }  @finally {
            result(nil);
        }
    } else if([@"hideBannerAd" isEqualToString:call.method]) {
        @try {
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<IBannerAd> bannerAd = self->mAdObjMap[@(objectId)];
            [bannerAd hide];
        }  @finally {
                result(nil);
            }
    }else if([@"destoryBannerAd" isEqualToString:call.method]){
        @try {  
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<IBannerAd> bannerAd = self->mAdObjMap[@(objectId)];
            [bannerAd destory];
            [self->mAdObjMap removeObjectForKey:@(objectId)];
        }  @finally {
            result(nil);
        }
    }else if([@"createRewardedVideoAd" isEqualToString:call.method]) {
        int objectId = [self genNumber];
        XRewardedVideoAdCallBack* callcallBack =  [[XRewardedVideoAdCallBack alloc] init];
        
        [callcallBack setChannel:self.eventSink :objectId];
        id<IRewardedVideoAd> videoAd = [XSDK createRewardedVideoAd:call.arguments :callcallBack];
        [self->mAdObjMap setObject:videoAd  forKey:@(objectId)];
        result(@(objectId));
        
    }else if([@"showRewardedVideoAd" isEqualToString:call.method]) {
        @try {
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<IRewardedVideoAd> videoAd  = self->mAdObjMap[@(objectId)];
            [videoAd show];
        }  @finally {
            result(nil);
        }
    }
    else if([@"destoryRewardedVideoAd" isEqualToString:call.method]) {
        @try {
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<IRewardedVideoAd> videoAd  = self->mAdObjMap[@(objectId)];
            [videoAd destory];
            [self->mAdObjMap removeObjectForKey:@(objectId)];
        }  @finally {
            result(nil);
        }
    }else if([@"createSplashAD" isEqualToString:call.method]) {
        int objectId = [self genNumber];
        XSplashAdCallBack* callBack =  [[XSplashAdCallBack alloc] init];
        
        [callBack setChannel:self.eventSink :objectId];
        id<ISplashAd> videoAd = [XSDK createSplashAD:call.arguments :callBack];
        [self->mAdObjMap setObject:videoAd  forKey:@(objectId)];
        result(@(objectId));
    }else if([@"destorySplashAd" isEqualToString:call.method]){
        @try {
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<ISplashAd> videoAd  = self->mAdObjMap[@(objectId)];
            [videoAd destory];
            [self->mAdObjMap removeObjectForKey:@(objectId)];
        }  @finally {
            result(nil);
        }
    }else if([@"showSplashAd" isEqualToString:call.method]){
        @try {
            NSError *error = nil;
            NSDictionary *data = [NSJSONSerialization JSONObjectWithData:[call.arguments dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
            
            if (![data objectForKey:@"objectId"]) return;
            int objectId = [data[@"objectId"] intValue];
            if (![self->mAdObjMap objectForKey:@(objectId)]) return;
            id<ISplashAd> videoAd  = self->mAdObjMap[@(objectId)];
            [videoAd show:[data[@"params"] stringValue]];
        }  @finally {
            result(nil);
        }
    }
    else {
        result(FlutterMethodNotImplemented);
    }
    
    /*
     * @Summary:程序被第三方调用，传入参数启动
     *
     */
}


#pragma mark - FlutterStreamHandler

- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(FlutterEventSink)eventSink {
    self.eventSink = eventSink;
    return nil;
}

- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments {
    self.eventSink = nil;
    return nil;
}


@end
